import boto3
import lmdb
import redis
from redis.cluster import RedisCluster
from botocore.client import Config
from botocore.exceptions import ClientError

from service.utils.download_file import download_file


class IDB:
    env = None
    is_initialized = False

    def initialize(self, path: str):
        """
        初始化LMDB环境。

        Args:
            path (str): LMDB数据库的路径。

        Returns:
            lmdb.Environment: 初始化后的LMDB环境。

        Notes:
            //t: 添加注释
            //r: 添加注释
            //n: 添加注释
        """
        self.env = lmdb.open(path)
        self.is_initialized = True
        return self.env

    def insert(self, sid, content):
        """
        向数据库中插入一条记录。

        参数:
        sid (int): ID。
        content (str): 内容。

        返回:
        None
        """
        if not self.is_initialized:
            return
        txn = self.env.begin(write=True)
        txn.put(str(sid).encode(), content.encode())
        txn.commit()

    def delete(self, sid):
        if not self.is_initialized:
            return
        txn = self.env.begin(write=True)
        txn.delete(str(sid).encode())
        txn.commit()

    def update(self, sid, name):
        if not self.is_initialized:
            return
        txn = self.env.begin(write=True)
        txn.put(str(sid).encode(), name.encode())
        txn.commit()

    def search(self, sid, decode=True):
        if not self.is_initialized:
            return
        txn = self.env.begin()
        name = txn.get(str(sid).encode())
        if decode:
            return name.decode()
        else:
            return name

    def display(self):
        if not self.is_initialized:
            return
        txn = self.env.begin()
        cur = txn.cursor()
        for key, value in cur:
            print(key, value)

    def has(self, key: str) -> bool:
        with self.env.begin() as txn:
            if txn.get(key.encode()) is not None:
                return True
            else:
                return False


class RDB:
    env = None
    is_initialized = False

    def initialize(self, host: str, port: int, db: int, pwd, cluster=False):
        self.env = redis.Redis(host=host, port=port, db=db, password=pwd)
        self.is_initialized = True
        return self.env

    # ❌ 集群的有问题
    def initialize_cluster(self, startup_nodes, pwd):
        RedisCluster(
            startup_nodes=startup_nodes,
        )

    def insert(self, k, v):
        if not self.is_initialized:
            return
        self.env.set(k, v)

    def delete(self, k):
        if not self.is_initialized:
            return
        self.env.delete(k)

    def update(self, sid, name):
        if not self.is_initialized:
            return

    def search(self, k):
        if not self.is_initialized:
            return
        self.env.get(k)

    def display(self):
        if not self.is_initialized:
            return


class S3:
    client: boto3.client = None
    bucket = "d3-engine"
    endpoint_url = ""

    def __init__(self, options):
        self.client = boto3.client(
            "s3",
            endpoint_url=options.get("endpoint"),
            aws_access_key_id=options.get("key_id"),
            aws_secret_access_key=options.get("access_key"),
            config=options.get("config") or Config(signature_version="s3v4"),
            region_name=options.get("region_name") or "us-east-1",
            verify=options.get("verify") or True,
            use_ssl=options.get("use_ssl") or True,
        )
        print("当前设置时区", options.get("region_name") or "us-east-1")
        self.endpoint_url = options.get("endpoint")

    def set_bucket(self, bucket):
        self.bucket = bucket

    def upload_file(self, target_path, file, force_check=True):
        self.client.upload_file(target_path, self.bucket, file, ACL="public-read")

    def upload_json(self, object_name, json: str):
        self.client.put_object(
            Key=object_name,
            Body=json,
            Bucket=self.bucket,
            ACL="public-read",
        )
        return self.endpoint_url + "/" + self.bucket + object_name

    def download_file(self, origin_path, target_path):
        try:
            # 下载文件
            self.client.download_file(self.bucket, origin_path, target_path)
            print(f"文件已下载到 {target_path}")
        except Exception as e:
            print(f"下载文件时出错: {e}")

    def check_if_exist(self, file_path):
        try:
            self.client.head_object(Bucket=self.bucket, Key=file_path)
            print("文件存在于 S3 中。")
            return True
        except ClientError as e:
            if e.response["Error"]["Code"] == "404":
                print("文件不存在于 S3 中。")
            else:
                print(f"检查文件时出错: {e}")
            return False


class EverDB:
    mode = ""
    engine = ""
    _instance = None
    options = None
    _m_type = 0
    S3 = None

    def __init__(self, mode: str, engine: str, options=None):
        if options is None:
            options = {}
        self.mode = mode
        self.engine = engine

        if mode == "local":
            self._instance = IDB()
            if options.get("path"):
                self._instance.initialize(options.get("path"))
            else:
                raise KeyError("缺少关键参数path")
        elif mode == "remote" and engine == "redis":
            self._instance = RDB()
            if (
                options.get("host")
                and options.get("port")
                and options.get("db")
                and options.get("pwd")
            ):
                self._instance.initialize(
                    options.get("host"),
                    options.get("port"),
                    options.get("db"),
                    options.get("pwd"),
                )
            else:
                raise KeyError("缺少关键参数")

    def save(self, key, value):
        self._instance.insert(key, value)

    def load(self, key):
        return self._instance.search(key)

    def has(self, key):
        return self._instance.has(key)

    def init_S3(self, ops):
        self.S3 = S3(ops)


print("EverDB扩展加载成功 版本v0.0.5")
